package com.easyapi.server.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easyapi.common.base.UserTokenThreadHolder;
import com.easyapi.common.enums.StatusCode;
import com.easyapi.common.enums.user.UserRole;
import com.easyapi.common.exception.BizException;
import com.easyapi.common.param.role.PageRoleParam;
import com.easyapi.common.param.role.RoleAddParam;
import com.easyapi.common.vo.user.ApiCenterUserVo;
import com.easyapi.common.vo.user.PageRoleVo;
import com.easyapi.common.vo.user.PermissionVo;
import com.easyapi.common.vo.user.RoleVo;
import com.easyapi.dao.entity.user.*;
import com.easyapi.dao.mapper.user.*;
import com.easyapi.server.service.user.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author javadadi
 */
@Service
@Slf4j
public class RoleServiceImpl extends ServiceImpl<ApiCenterRoleMapper, ApiCenterRole> implements RoleService {
    @Resource
    private ApiCenterRoleMapper roleMapper;
    @Resource
    private ApiCenterRoleUserMapper roleUserMapper;
    @Resource
    private ApiCenterRolePermissionMapper rolePermissionMapper;
    @Resource
    private ApiCenterPermissionMapper permissionMapper;
    @Resource
    private ApiCenterUserMapper userMapper;

    /*using by controller*/
    /**
     * 获取用户的角色
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<RoleVo> listRoleVosByUserId(Long userId) {
        List<Long> roleIds = roleUserMapper.getRoleIdsByUserId(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return new ArrayList<RoleVo>();
        }
        List<ApiCenterRole> roleList = roleMapper.selectBatchIds(roleIds);
        return roleList.stream()
                .distinct()
                .map(m -> RoleVo.builder()
                        .roleDesc(m.getRoleDesc())
                        .roleName(m.getRoleName())
                        .id(m.getId())
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * 获取用户没有授予的角色
     *
     * @return  List<RoleVo>
     */
    @Override
    public List<RoleVo> listUserExRoles(Long userId) {
        ApiCenterUser user = userMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new BizException(StatusCode.NO_SUCH_USER);
        }
        List<Long> ids = roleUserMapper.getRoleIdsByUserId(userId);
        List<ApiCenterRole> roleList = roleMapper.listRoles();
        return roleList.stream()
                .filter(m -> !Objects.equals(m.getRoleName(), UserRole.ADMIN.getRoleName())
                                && !ids.contains(m.getId()))
                .map(m -> RoleVo.builder()
                        .id(m.getId())
                        .roleName(m.getRoleName())
                        .roleDesc(m.getRoleDesc())
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * 获取角色已经拥有的权限
     *
     * @param roleId
     * @return
     */
    @Override
    public List<PermissionVo> listPermissionsByRoleId(Long roleId) {
        ApiCenterRole role = getById(roleId);
        if (Objects.isNull(role)) {
            throw new BizException(StatusCode.NO_SUCH_ROLE);
        }
        return rolePermissionMapper.getPermissionsByRoleIds(Collections.singletonList(roleId));
    }

    /**
     * 获取当前角色没有授权的权限
     *
     * @return
     */
    @Override
    public List<PermissionVo> listRoleExPermission(Long roleId) {
        ApiCenterRole role = getById(roleId);
        if (Objects.isNull(role)) {
            throw new BizException(StatusCode.NO_SUCH_ROLE);
        }
        List<PermissionVo> roleExPermission = permissionMapper.listAllPermission();
        Map<Long, PermissionVo> map = rolePermissionMapper.
                getPermissionsByRoleIds(Collections.singletonList(roleId))
                .stream().collect(Collectors.toMap(PermissionVo::getId, Function.identity()));
        return roleExPermission.stream()
                .filter((m) -> !map.containsKey(m.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 新建|更新角色
     *
     * @param param 新建|更新角色
     *              <p>id 用户id</p>
     *              <p>roleName 角色名称</p>
     *              <p>roleDesc 角色描述</p>
     *              <p>projectId 项目id</p>
     * @return true
     */
    @Override
    public boolean saveRole(RoleAddParam param) {
        Long id = param.getId();
        ApiCenterRole role = null;
        String roleName = param.getRoleName();
        String roleDesc = param.getRoleDesc();
        Long projectId = param.getProjectId();
        if (!Objects.isNull(id)) {
            role = roleMapper.selectById(id);
            if (Objects.isNull(role)) {
                throw new BizException(StatusCode.NO_SUCH_ROLE);
            }
        }
        if (StringUtils.isEmpty(roleName)) {
            throw new BizException(StatusCode.PARAMS_ERROR);
        }
        ApiCenterUserVo currentUser = UserTokenThreadHolder.getCurrentUser();
        if (Objects.isNull(id)) {
            role = ApiCenterRole
                    .builder()
                    .roleName(roleName)
                    .roleDesc(roleDesc)
                    .roleType(1)
                    .projectId(projectId)
                    .build();
            role.setCreateBy(currentUser.getId());
            role.setUpdateBy(currentUser.getId());
            roleMapper.insert(role);
        } else {
            role.setRoleName(roleName);
            role.setRoleDesc(roleDesc);
            roleMapper.updateById(role);
        }
        return true;
    }

    /**
     * 授予角色权限
     *
     * @param roleId       角色id
     * @param permissionId 权限id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addRolePermission(Long roleId, Long permissionId) {
        ApiCenterRole role = roleMapper.selectById(roleId);
        if (Objects.isNull(role)) {
            throw new BizException(StatusCode.NO_SUCH_ROLE);
        }
        ApiCenterPermission apiCenterPermission = permissionMapper.selectById(permissionId);
        if (Objects.isNull(apiCenterPermission)) {
            throw new BizException(StatusCode.NO_SUCH_PERMISSION);
        }
        //只有自己创建的角色才能够授权
        ApiCenterUserVo currentUser = UserTokenThreadHolder.getCurrentUser();
        if (!Objects.equals(role.getCreateBy(), currentUser.getId())) {
            throw new BizException(StatusCode.NO_AUTH_ERROR);
        }
        ApiCenterRolePermission rolePermission = rolePermissionMapper.getByRoleIdAndPermissionId(roleId, permissionId);
        if (Objects.nonNull(rolePermission)) {
            throw new BizException(StatusCode.REPEAT_PERMISSION);
        }
        ApiCenterRolePermission apiCenterRolePermission = new ApiCenterRolePermission();
        apiCenterRolePermission.setPermissionId(permissionId);
        apiCenterRolePermission.setRoleId(roleId);
        rolePermissionMapper.insert(apiCenterRolePermission);
        return true;
    }

    /**
     * 删除角色的授权信息
     *
     * @param roleId       角色id
     * @param permissionId 授权id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean delRolePermission(Long roleId, Long permissionId) {
        ApiCenterRole role = getById(roleId);
        if (Objects.isNull(role)) {
            throw new BizException(StatusCode.NO_SUCH_ROLE);
        }
        ApiCenterPermission permission = permissionMapper.selectById(permissionId);
        if (Objects.isNull(permission)) {
            throw new BizException(StatusCode.NO_SUCH_PERMISSION);
        }
        Long createBy = role.getCreateBy();
        //自己创建的角色才能够取消授权
        ApiCenterUserVo currentUser = UserTokenThreadHolder.getCurrentUser();
        if (!Objects.equals(createBy, currentUser.getId())) {
            throw new BizException(StatusCode.NO_AUTH_ERROR);
        }
        ApiCenterRolePermission roleIdAndPermissionId = rolePermissionMapper.getByRoleIdAndPermissionId(roleId, permissionId);
        if (Objects.isNull(roleIdAndPermissionId)) {
            throw new BizException(StatusCode.NO_SUCH_PERMISSION_MESSAGE);
        }
        rolePermissionMapper.deleteByRoleIdAndPermissionId(roleId, permissionId);
        return true;
    }

    /**
     * 角色删除
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteRole(Long id) {
        ApiCenterRole role = getById(id);
        if (Objects.isNull(role)) {
            throw new BizException(StatusCode.NO_SUCH_ROLE);
        }
        //查看是否有用户正在引用这个角色
        List<ApiCenterRoleUser> roleUsers = roleUserMapper.getByRoleId(role.getId());
        if (CollectionUtils.isNotEmpty(roleUsers)) {
            throw new BizException(StatusCode.ROLE_IS_REFERENCED);
        }
        roleMapper.deleteById(id);
        rolePermissionMapper.deleteByRoleId(role.getId());
        return true;
    }

    /**
     * 分页获取角色信息
     *
     * @param param 参数
     *              <p>roleName 角色名称</p>
     *              <p>roleId 角色Id</p>
     *              <p>createBy 创建人Id</p>
     *              <p>roleType 角色类型</p>
     * @return
     */
    @Override
    public Page<PageRoleVo> page(PageRoleParam param) {
        Page<ApiCenterRole> page = new Page<>(param.getCurrent(), param.getSize());
        LambdaQueryWrapper<ApiCenterRole> wrapper = new LambdaQueryWrapper<ApiCenterRole>()
                .like(StringUtils.isNotEmpty(param.getRoleName()), ApiCenterRole::getRoleName, param.getRoleName())
                .eq(Objects.nonNull(param.getRoleType()), ApiCenterRole::getRoleType, param.getRoleType())
                .eq(Objects.nonNull(param.getCreateBy()), ApiCenterRole::getCreateBy, param.getCreateBy());
        Page<ApiCenterRole> apiCenterRolePage = roleMapper.selectPage(page, wrapper);
        List<PageRoleVo> roleVos = apiCenterRolePage.getRecords().stream().map(m -> {
            PageRoleVo roleVo = PageRoleVo.builder()
                    .id(m.getId())
                    .roleName(m.getRoleName())
                    .roleDesc(m.getRoleDesc())
                    .roleValue(m.getRoleValue())
                    .createAt(m.getCreateAt())
                    .updateAt(m.getUpdateAt())
                    .roleType(m.getRoleType()).build();
            ApiCenterUser createUser = userMapper.selectById(m.getCreateBy());
            ApiCenterUser updateUser = userMapper.selectById(m.getUpdateBy());
            roleVo.setCreateBy(Objects.isNull(createUser) ? 0 : createUser.getId());
            roleVo.setCreateUserName(Objects.isNull(createUser) ? "---" : createUser.getUserName());
            roleVo.setUpdateBy(Objects.isNull(updateUser) ? 0 : updateUser.getId());
            roleVo.setUpdateUserName(Objects.isNull(updateUser) ? "---" : updateUser.getUserName());
            return roleVo;
        }).collect(Collectors.toList());
        Page<PageRoleVo> resultPage = new Page<>(apiCenterRolePage.getCurrent(), apiCenterRolePage.getSize(), apiCenterRolePage.getTotal());
        resultPage.setRecords(roleVos);
        return resultPage;
    }


    /**
     * 获取用户权限
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<PermissionVo> getPermissionByUserId(Long userId) {
        List<Long> roleIds = roleUserMapper.getRoleIdsByUserId(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        List<PermissionVo> permissions = rolePermissionMapper.getPermissionsByRoleIds(roleIds);
        return permissions;
    }

    /**
     * 查询用户的角色
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<String> getRolesByUserId(Long userId) {
        List<Long> roleIds = roleUserMapper.getRoleIdsByUserId(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        List<ApiCenterRole> roles = roleMapper.getRolesByUserId(roleIds);
        List<String> names = roles.stream().map(ApiCenterRole::getRoleName).collect(Collectors.toList());
        return names;
    }

    /**
     * 授予用户角色
     *
     * @param user
     * @return
     */
    @Override
    public boolean saveDefaultRole(ApiCenterUser user) {
        //默认赋予visitor 角色
        ApiCenterRole role = this.getOne(new LambdaQueryWrapper<ApiCenterRole>().eq(ApiCenterRole::getRoleName, UserRole.VISITOR.getRoleName()));
        ApiCenterRoleUser roleUser = new ApiCenterRoleUser();
        roleUser.setUserId(user.getId());
        roleUser.setRoleId(role.getId());
        roleUserMapper.insert(roleUser);
        return true;
    }


    /**
     * 用户角色授权
     *
     * @param roleId 角色id
     * @param userId 用户id
     * @return true
     */
    @Override
    public boolean addRoleUsersByRoleIdAndUserId(Long roleId, Long userId) {
        ApiCenterRole role = roleMapper.selectById(roleId);
        if (Objects.isNull(role)) {
            log.error("empower user error no such role as roleId==>{}", roleId);
            return true;
        }
        if (Objects.equals(roleId, UserRole.ADMIN.getId())) {
            throw new BizException(StatusCode.NO_AUTH_ERROR);
        }
        ApiCenterRoleUser byUserIdAndRoleId = roleUserMapper.getByUserIdAndRoleId(roleId, userId);
        if (Objects.nonNull(byUserIdAndRoleId)) {
            log.error("empower user error because is exist ==>{}", byUserIdAndRoleId);
            throw new BizException(StatusCode.OPERATION_ERROR);
        }
        ApiCenterRoleUser roleUser = new ApiCenterRoleUser();
        roleUser.setRoleId(roleId);
        roleUser.setUserId(userId);
        roleUserMapper.insert(roleUser);
        return true;
    }


    /**
     * 取消用户的角色
     *
     * @param roleId 角色id
     * @param userId 用户id
     * @return true
     */
    @Override
    public boolean delRoleUsersRoleIdAndUserId(Long roleId, Long userId) {
        ApiCenterRole role = roleMapper.selectById(roleId);
        if (Objects.isNull(role)) {
            log.error("revoke user error no such role as roleId==>{}", roleId);
            return true;
        }
        //管理员不能够移除也不能授权给别人
        if (Objects.equals(roleId, UserRole.ADMIN.getId())) {
            throw new BizException(StatusCode.NO_AUTH_ERROR);
        }
        //默认角色不能够取消
        if (Objects.equals(roleId, UserRole.VISITOR.getId())) {
            throw new BizException(StatusCode.VISITOR_CANNOT_DEL);
        }
        roleUserMapper.delRoleUserByUserIdAndRoleId(userId, roleId);
        return true;
    }
}
